package com.rightrule.rule.component;

import com.alibaba.fastjson.JSONObject;
import com.rightrule.entity.*;
import com.rightrule.rule.constans.RuleFlowNodeTypeEnum;
import com.rightrule.rule.dto.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Component
@Slf4j
@Data
public class PackPackageComponent {

    /**
     * 从数据库中打包出运行的策略包 todo 后续需要优化打包和解析包合并，最终输出可运行包
     *
     * @param strategyId
     * @param strategyVersionId
     * @return
     */
    public StrategyVersionPkgDTO packPackage(Long strategyId, Long strategyVersionId) {

        StrategyVersionPkgDTO strategyVersionPkgDTO = new StrategyVersionPkgDTO();

        // todo 查询数据库中对应的策略信息，有异常直接抛出
        DecisionStrategyEntity strategyEntity = new DecisionStrategyEntity();

        // todo 查询数据库中对应的策略版本信息，有异常直接抛出
        DecisionStrategyVersionEntity strategyVersionEntity = new DecisionStrategyVersionEntity();

        // todo 查询当前版本下面的输入变量并且转换，有异常直接抛出
        List<DecisionFieldEntity> inputFields = new ArrayList<>();
        List<DecisionFieldDTO> inputFieldDtos = new ArrayList<>();

        // todo 查询当前版本下面的输出变量并且转换，有异常直接抛出
        List<DecisionFieldEntity> outputFields = new ArrayList<>();
        List<DecisionFieldDTO> outputFieldDtos = new ArrayList<>();

        // todo 查询当前版本下面的中间变量并且转换,有异常直接抛出
        List<DecisionFieldEntity> midFields = new ArrayList<>();
        List<DecisionFieldDTO> midFieldDts = new ArrayList<>();

        // todo 查询当前版本下面的事件变量并且转换，有异常则直接抛出
        List<DecisionFieldEntity> eventFields = new ArrayList<>();
        List<DecisionFieldDTO> eventFieldDtos = new ArrayList<>();


        // todo 查询当前版本下面的规则流(除了主规则流，还有子规则流),有异常则直接抛出
        List<DecisionRuleFlowEntity> ruleFlows = new ArrayList<>();

        // todo 查询当前版本下面的所有规则
        ArrayList<DecisionRuleEntity> rules = new ArrayList<>();

        // 规则list转换为map，key为规则id
        Map<Long, DecisionRuleEntity> ruleMap = rules.stream().collect(Collectors.toMap(DecisionRuleEntity::getId, decisionRuleEntity -> decisionRuleEntity));

        // 前置数据准备完成，开始打包

        // 准备好子规则流数据集
        HashMap<String, RuleFlowSnapshotDTO> subRuleFlowSnapshot = new HashMap<>();

        // 遍历所有规则流
        for (DecisionRuleFlowEntity ruleFlow : ruleFlows) {
            // 如果是主规则流则打包主规则流逻辑
            if (Long.valueOf(0).equals(ruleFlow.getParentFlowId().longValue())) {

                RuleFlowSnapshotDTO ruleFlowSnapshotDTO = packRuleFlowAndGet(ruleFlow, ruleMap);

                BeanUtils.copyProperties(strategyEntity, strategyVersionPkgDTO);
                strategyVersionPkgDTO.setStrategyId(strategyId);
                strategyVersionPkgDTO.setStrategyVersionId(strategyVersionId);
                strategyVersionPkgDTO.setRuleFlow(ruleFlowSnapshotDTO);
                strategyVersionPkgDTO.setInputFields(inputFieldDtos);
                strategyVersionPkgDTO.setEventFields(eventFieldDtos);
                strategyVersionPkgDTO.setOutputFields(outputFieldDtos);
                strategyVersionPkgDTO.setMidFields(midFieldDts);
                strategyVersionPkgDTO.setStrategyCode(strategyEntity.getStrategyCode());
                strategyVersionPkgDTO.setVersionDesc(strategyVersionEntity.getVersionDesc());
            }
            // 如果是子规则流则打包子规则流逻辑
            else {
                // 打包主规则流
                RuleFlowSnapshotDTO subRuleFlowSnapshotDTO = packRuleFlowAndGet(ruleFlow, ruleMap);
                subRuleFlowSnapshot.put(ruleFlow.getId().toString(), subRuleFlowSnapshotDTO);
            }
        }

        strategyVersionPkgDTO.setSubRuleFlowMaps(subRuleFlowSnapshot);
        return strategyVersionPkgDTO;
    }


    /**
     * 规则流打包逻辑
     *
     * @param ruleFlow
     * @param ruleMap
     * @return
     */
    private RuleFlowSnapshotDTO packRuleFlowAndGet(DecisionRuleFlowEntity ruleFlow, Map<Long, DecisionRuleEntity> ruleMap) {
        RuleFlowSnapshotDTO ruleFlowSnapshotDTO = new RuleFlowSnapshotDTO();

        // 设置规则流属性
        BeanUtils.copyProperties(ruleFlow, ruleFlowSnapshotDTO);

        // 规则流对应的所有节点
        HashMap<String, RuleFlowNodeSnapshotDTO> allNodesSnapshot = new HashMap<>();

        List<RuleFlowNodeSnapshotDTO> ruleFlowNodeSnapshotDTOS = new ArrayList<>();

        // 解析规则流逻辑结构
        try {
            ruleFlowNodeSnapshotDTOS = JSONObject.parseArray(ruleFlow.getFlowLogic(), RuleFlowNodeSnapshotDTO.class);
        }
        // 解析规则流异常
        catch (Exception e) {
            log.error("parse flowLogic error,flowId={}", ruleFlow.getId());
            throw new RuntimeException("flow node list error");
        }

        // 节点列表为空
        if (CollectionUtils.isEmpty(ruleFlowNodeSnapshotDTOS)) {
            throw new RuntimeException("flow node list error");
        }

        // 是否存在开始和结束节点
        boolean hasBeginNode = false, hasEndNode = false;

        for (RuleFlowNodeSnapshotDTO ruleFlowNodeSnapshotDTO : ruleFlowNodeSnapshotDTOS) {

            // 开始节点
            if (RuleFlowNodeTypeEnum.START.getCode().equals(ruleFlowNodeSnapshotDTO.getNodeType())) {
                // 设置为规则流的开始节点
                ruleFlowSnapshotDTO.setStartNode(ruleFlowNodeSnapshotDTO);
                hasBeginNode = true;
            }

            // 结束节点
            if (RuleFlowNodeTypeEnum.END.getCode().equals(ruleFlowNodeSnapshotDTO.getNodeType())) {
                allNodesSnapshot.put(ruleFlowNodeSnapshotDTO.getNodeId().toString(), ruleFlowNodeSnapshotDTO);
                hasEndNode = true;
            }

            // 执行节点
            else if (RuleFlowNodeTypeEnum.EXECUTE.getCode().equals(ruleFlowNodeSnapshotDTO.getNodeType())) {

                // 执行节点没有对应的规则
                if (!ruleMap.containsKey(ruleFlowNodeSnapshotDTO.getRuleId())) {
                    throw new RuntimeException("release node to rule error");
                }

                // 设置ruleInfo
                DecisionRuleDTO decisionRuleDTO = new DecisionRuleDTO();
                BeanUtils.copyProperties(ruleMap.get(ruleFlowNodeSnapshotDTO.getRuleId()), decisionRuleDTO);
                ruleFlowNodeSnapshotDTO.setRuleInfo(decisionRuleDTO);
                allNodesSnapshot.put(ruleFlowNodeSnapshotDTO.getNodeId().toString(), ruleFlowNodeSnapshotDTO);
            }
            // 其他节点（包含子规则流节点）
            else {
                allNodesSnapshot.put(ruleFlowNodeSnapshotDTO.getNodeId().toString(), ruleFlowNodeSnapshotDTO);
            }
        }

        // 如果缺少开始节点和结束节点
        if (!hasBeginNode || !hasEndNode) {
            throw new RuntimeException("release node to rule error");
        }

        // 设置规则流除了开始节点以外的所有节点
        ruleFlowSnapshotDTO.setNodes(allNodesSnapshot);
        return ruleFlowSnapshotDTO;
    }
}
